package cz.cuni.amis.pogamut.episodic.decisions;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

/**
 * Class <code>Intention</code> represents an intention node from decision process
 * in pogamut end of the project. It is part of decision tree and represent
 * universal AND node in the decision AND-OR trees. In order to fulfill
 * an intention, any of it's sub-actions can be performed and all intentions (goals)
 * are needed to perform one given super-action. It is extending
 * the <code>Node</code> class, so it is possible to attach specified
 * affordances to the <code>Intention</code> node.
 * <p>
 * By pointing to the trace of <code>Intention</code>s and <code>Action</code>s
 * it is possible to add new node to the episode tree. It is the only way how
 * to add new information to memory.
 * <p>
 * <code>AtomicAction</code> nodes can be attached on to <code>Action</code>
 * nodes. They cannot be attached to the <code>Intention</code> nodes.
 *
 * @author Michal Cermak
 * @see Node
 */
public class Intention extends Node implements Serializable {
    /**
     * Determines if a de-serialized file is compatible with this class.
     *
     * Maintainers must change this value if and only if the new version
     * of this class is not compatible with old versions. See Sun docs
     * for <a href=http://java.sun.com/products/jdk/1.1/docs/guide
     * /serialization/spec/version.doc.html> details. </a>
     *
     * Not necessary to include in first version of the class, but
     * included here as a reminder of its importance.
     */
    private static final long serialVersionUID = 1L;

    int possibleSubTrees = 0;

    /**
     * Each <code>Intention</code> node can have unlimited number of <code>Action</code>
     * subnodes. The only restriction is that no two subnodes can have identical
     * name. These subnodes are actions that can be performed in order
     * to satisfy this intention - they are OR nodes.
     */
    private HashMap<String,Action> subNodes = new HashMap<String, Action>();

    /**
     * Instantiate the class by providing its name and attractivity.
     * <p>
     * There can be several nodes with identical name in the decision tree,
     * but no node can have two direct children with the same name.
     *
     * @param   name    Name of the new node.
     * @param   _attractivity   Specified in XML file. Helps determine when to forget node.
     */
    public Intention(String name, int attractivity) {
        super(name, attractivity, NodeType.INTENTION);
    }

    /**
     * Adds a new action subnode that can be performed in order to satisfy
     * the goal representing by the current node. Each <code>Intention</code>
     * node can have unlimited number of <code>Action</code> subnodes.
     * The only restriction is that no two direct subnodes can have identical
     * name.  These subnodes are actions that can be performed in order
     * to satisfy this intention - they are OR nodes.
     * <p>
     * This method is used to create the decision tree structure during memory
     * initialization.
     * <p>
     * No direct goal subnode can share identical name with attached atomic
     * action node.
     *
     * @param   action   Reference to an already instanciated <code>Action</code>
     * class that should be added attached to this <code>Intention</code> node.
     */
    public void addSubNode(Action action) {
        subNodes.put(action.getName(), action);
        action.parent = this;
    }

    /**
     * Basically a getter method for the <code>subNodes</code> variable.
     * These subnodes are actions, any of which can be performed in order
     * to satisfy this intention(goal) - they are OR nodes. Together with
     * attached affordances they are direct children of this node
     * in the decision tree.
     *
     * @return Returns a collection of a all <code>Action</code>
     * subnodes of this <code>Intention</code> node.
     */
    public Collection<Action> getSubNodes() {
        return subNodes.values();
    }

    /**
     * This method returns one specified <code>Action</code> node that
     * is direct subnode of this node.
     *
     * @param   name    Name of the node that is to be returned.
     * @return Returns an <code>Action</code> node with specified
     * name that is direct subnode of this <code>Intention</code> node.
     * If no such action exists returns <code>null</code>.
     */
    @Override
    public Node getSubNode(String name) {
        return subNodes.get(name);
    }

    /**
     * This method returns all <code>Action</code> node that
     * is direct subnodes of this node.
     *
     * @return Returns all <code>Action</code> nodes that are direct subnodes
     * of this <code>Intention</code> node.
     * If no such action exists returns empty collection.
     */
    @Override
    public Collection<Node> getAllChildrenNodes() {
        Collection<Node> col = new HashSet<Node>();
        col.addAll(subNodes.values());
        return col;
    }

    public int  getPossibleSubTrees() {
        if (possibleSubTrees == 0) {
            for (Action a : getSubNodes()) {
                possibleSubTrees += a.getPossibleSubTrees();
            }
        }
        return possibleSubTrees;
    }
}
